#ifndef DIALOG_H_
#define DIALOG_H_

#include <gtkmm.h>

#include "conf.h"
#include "yellowpage.h"
#include "widgets.h"
#include "options.h"
#include "loader.h"
#include "misc.h"

namespace gpyp {

class Application;

class UptestDialog : public Gtk::Dialog {
private:
  enum Status {
    STATUS_NONE,
    STATUS_PREPARING,
    STATUS_UNTESTABLE,
    STATUS_READY,
    STATUS_TESTING,
    STATUS_ERROR
  };

  class Provider : boost::noncopyable {
  private:
    sigc::signal<void, Status> signal_status_changed_;
  public:
    inline sigc::signal<void, Status> signal_status_changed() {
      return signal_status_changed_;
    }

  protected:
    static Gdk::Color _color_green;
    static Gdk::Color _color_red;

  private:
    Application     &app_;

    RefYellowPage    yp_;
    Status           status_;

  protected:
    virtual void on_prepare(RefYellowPage yp) = 0;
    virtual void on_test() = 0;

    void set_status(Status status);

    static void set_color(Gtk::Widget &widget, boost::logic::tribool b);
    static void set_bool(Gtk::Label &label, bool value);

  public:
    inline RefYellowPage get_yp() {
      return yp_;
    }
    inline void set_yp(RefYellowPage yp) {
      yp_ = yp;
      on_prepare(yp_);
    }

    inline void test() {
      on_test();
    }

  protected:
    Provider(Application &app);
  public:
    virtual ~Provider();
  };

  class YP4G : public Provider,
               public conf::ParserBase,
               public Gtk::Table {
  private:
    typedef loader::RefError RefError;
    typedef loader::RefResponse RefResponse;

  private:
    struct Data {
      Glib::ustring yp_name;

      Glib::ustring host_ip;
      bool          host_port_open;
      int           host_speed;
      bool          host_over;

      bool          uptest_checkable;
      int           uptest_remain;

      Glib::ustring srv_addr;
      int           srv_port;
      Glib::ustring srv_object;
      int           srv_post_size;
      int           srv_limit;
      int           srv_interval;
      bool          srv_enabled;

      inline Data() :
        host_port_open  (false),
        host_speed      (-1),
        host_over       (false),

        uptest_checkable(false),
        uptest_remain   (-1),

        srv_port        (-1),
        srv_post_size   (-1),
        srv_limit       (-1),
        srv_interval    (-1),
        srv_enabled     (false)
      {
      }
    };

  private:
    URL   url_;

    Gtk::Label l_yp_name_;
    Gtk::Label l_host_ip_;
    Gtk::Label l_host_port_open_;
    Gtk::Label l_host_speed_;
    Gtk::Label l_host_over_;
    Gtk::Label l_uptest_checkable_;
    Gtk::Label l_uptest_remain_;
    Gtk::Label l_srv_addr_;
    Gtk::Label l_srv_port_;
    Gtk::Label l_srv_object_;
    Gtk::Label l_srv_post_size_;
    Gtk::Label l_srv_limit_;
    Gtk::Label l_srv_interval_;
    Gtk::Label l_srv_enabled_;

    Gtk::Label d_yp_name_;
    Label      d_host_ip_;
    Gtk::Label d_host_port_open_;
    Gtk::Label d_host_speed_;
    Gtk::Label d_host_over_;
    Gtk::Label d_uptest_checkable_;
    Gtk::Label d_uptest_remain_;
    EntryLabel d_srv_addr_;
    EntryLabel d_srv_port_;
    EntryLabel d_srv_object_;
    Gtk::Label d_srv_post_size_;
    Gtk::Label d_srv_limit_;
    Gtk::Label d_srv_interval_;
    Gtk::Label d_srv_enabled_;

    boost::shared_ptr<Data> data_;

    time_t           remain_time_;
    sigc::connection conn_remain_timer_;

    loader::RefConnection loader_conn_;

  protected:
    virtual void on_start_element(const char  *element_name,
                                  const char **attribute_names,
                                  const char **attribute_values,
                                  GError     **error);

    void loader_on_error(const RefError &err);
    void error(const Glib::ustring &message);

    bool is_checkable();
    bool remain_timeout();

    void clear();
    void on_information_loaded(const RefResponse response);
    void update_information();

    virtual void on_prepare(RefYellowPage yp);
    void on_test_complete(const RefResponse response);
    virtual void on_test();

  public:
    YP4G(Application &app);
    virtual ~YP4G();
  };

  Application  &app_;

  Gtk::Image    yp_icon_;
  Gtk::Button   yp_button_;
  SelectorComboBox<RefYellowPage> yp_selector_;
  Gtk::HBox     yp_box_;

  YP4G          yp4g_;
  Gtk::Label    l_unsupported_;
  Gtk::Label    l_unselected_;

  Gtk::Label    l_status_;
  Gtk::Button  *b_test_;

protected:
  virtual void yp_button_on_clicked();
  virtual void yp_selector_on_selected(RefYellowPage yp);

  virtual void yp4g_on_status_changed(Status status);

  virtual void on_response(int response_id);

public:
  void set(RefYellowPage yp);

  UptestDialog(Application &app, Gtk::Window &parent);
};

class ChPropertyView : public TextView {
private:
  bool       set_mark_;
  RefChannel ch_;

protected:
  virtual void prepare_commandopts(CommandOpts &opts);

  virtual Gdk::Rectangle *
  on_show_property(Glib::RefPtr<Gtk::TextBuffer> buf,
                   RefChannel                    ch,
                   const Channel::Property      *prop,
                   Gdk::Rectangle               &rect);

public:
  void set(RefChannel ch);

  void refresh();

  ChPropertyView(Application &app, bool set_mark = false);
};

class FavoriteMatchView : public Gtk::HPaned {
private:
  class PropertyView : public ChPropertyView {
  protected:
    virtual Gdk::Rectangle *
    on_show_property(Glib::RefPtr<Gtk::TextBuffer> buf,
                     RefChannel                    ch,
                     const Channel::Property      *prop,
                     Gdk::Rectangle               &rect);

  public:
    PropertyView(Application &app, bool set_mark = false);
  };

private:
  Gtk::TreeModelColumn<Glib::ustring> model_column_name_;
  Gtk::TreeModelColumn<RefFavorite>   model_column_favorite_;
  Gtk::TreeModelColumn<RefRule>       model_column_rule_;
  Gtk::TreeModelColumnRecord          columns_;
  Glib::RefPtr<Gtk::TreeStore>        model_;

  Gtk::CellRendererText      renderer_name_;
  Gtk::TreeViewColumn        column_name_;
  TreeView                   treeview_;
  Gtk::ScrolledWindow        sw_treeview_;
  PropertyView               propview_;
  Gtk::ScrolledWindow        sw_propview_;
  Glib::RefPtr<Gtk::TextTag> tag_matched_;

  RefChannel ch_;

  void highlight(conf::RefAttributeBool   target,
                 RefRegex                 re,
                 const Channel::Property &prop);
  void highlight(RefRule rule);

  void selected();

public:
  void set(RefChannel ch);

  FavoriteMatchView(Application &app);
};

class ChInfoDialog : public Gtk::Dialog {
private:
  Application          &app_;

  Gtk::Label            l_yp_;
  Gtk::Label            d_yp_;
  Gtk::Label            l_created_;
  Gtk::Label            d_created_;
  Gtk::Label            l_last_played_;
  Gtk::Label            d_last_played_;
  Gtk::Label            l_ended_;
  Gtk::Label            d_ended_;
  Gtk::Label            l_flags_;
  Gtk::Label            d_flags_;
  Gtk::Table            table_info_;

  FavoriteMatchView     favmatch_;
  ChPropertyView        propview_;
  Gtk::ScrolledWindow   sw_propview_;
  Gtk::Notebook         notebook_;

  sigc::connection      conn_channel_selected_;

  static void set_time(Gtk::Label                     &label,
                       const boost::posix_time::ptime &time);

public:
  void set(RefChannel ch);

  ChInfoDialog(Application &app, Gtk::Window &parent);
  virtual ~ChInfoDialog();
};

class YPInfoDialog : public Gtk::Dialog {
private:
  class YPTextView : public TextView {
  private:
    YPInfoDialog &dialog_;

  protected:
    virtual void prepare_commandopts(CommandOpts &opts);

  public:
    YPTextView(Application &app, YPInfoDialog &dialog);
  };

private:
  Application              &app_;

  RefYellowPage             yp_;
  Glib::RefPtr<Gdk::Pixbuf> icon_pixbuf_;

  Gtk::Image                icon_;
  EntryLabel                name_;
  Gtk::HBox                 name_box_;
  EntryLabel                url_;

  Gtk::Label                l_chcount_;
  Gtk::Label                d_chcount_;
  Gtk::Label                l_chcount_valid_;
  Gtk::Label                d_chcount_valid_;
  Gtk::Label                l_last_loaded_;
  Gtk::Label                d_last_loaded_;
  Gtk::Label                l_data_size_;
  Gtk::Label                d_data_size_;
  Gtk::Table                table_info_;

  YPTextView                request_;
  Gtk::ScrolledWindow       sw_request_;

  YPTextView                response_;
  Gtk::ScrolledWindow       sw_response_;

  YPTextView                source_;
  Gtk::ScrolledWindow       sw_source_;

  Gtk::Notebook             notebook_;

protected:
  virtual void on_response(int response_id);

private:
  static void setup_textview(Gtk::TextView &tv,
                             Gtk::ScrolledWindow &sw);

public:
  void set(RefYellowPage yp);

  YPInfoDialog(Application &app, Gtk::Window &parent);
};

class ConfigView : public Gtk::VBox {
private:
  Gtk::TreeModelColumnRecord          model_columns_;
  Gtk::TreeModelColumn<conf::RefNode> model_column_node_;
  Gtk::TreeModelColumn<Glib::ustring> model_column_name_;
  Gtk::TreeModelColumn<bool>          model_column_visible_;

  Glib::RefPtr<Gtk::TreeStore>        model_;
  Glib::RefPtr<Gtk::TreeModelFilter>  filter_;

  Gtk::CellRendererText renderer_name_;
  Gtk::CellRendererText renderer_value_;

  Gtk::TreeViewColumn   column_name_;
  Gtk::TreeViewColumn   column_value_;
  TreeView              view_;
  Gtk::ScrolledWindow   sw_view_;

  RefSearch search_;
  SearchBox search_box_;

  void create_tree(Gtk::TreeIter    iter,
                   conf::RefElement element);

  bool set_visible(Gtk::TreeIter iter, RefRegex re);

  void renderer_name_on_cell_data(Gtk::CellRenderer   *cell,
                                  const Gtk::TreeIter &iter);
  void renderer_value_on_cell_data(Gtk::CellRenderer   *cell,
                                   const Gtk::TreeIter &iter);
  void renderer_value_on_edited(const Glib::ustring &path,
                                const Glib::ustring &new_text);

protected:
  virtual bool on_key_press_event(GdkEventKey *event);
  virtual void search_on_changed();
  virtual void search_box_on_hide();

public:
  ConfigView(Application &app);
};

class ConfigViewDialog : public Gtk::Dialog {
private:
  ConfigView view_;

public:
  ConfigViewDialog(Application &app, Gtk::Window &parent);
};

class HelpBCDialog : public Gtk::Dialog {
private:
  TextView            view_;
  Gtk::ScrolledWindow sw_view_;

private:
  void enum_commands(const Glib::ustring &comm, BuiltinCommand &bc, int *right);

public:
  HelpBCDialog(Application &app, Gtk::Window &parent);
};

class HelpOptionDialog : public Gtk::Dialog {
private:
  TextView view_;

public:
  HelpOptionDialog(Application &app, Gtk::Window &parent);
};

class EnvInfoDialog : public Gtk::Dialog {
private:
  typedef struct {
    const char *name_;
    Glib::ustring (*func_)();
  } InfoTable;

  static InfoTable _info_tables[];

  TextView            view_;
  Gtk::ScrolledWindow sw_view_;

  static Glib::ustring i_version();
  static Glib::ustring i_svnversion();
  static Glib::ustring i_configure();
  static Glib::ustring i_build_time();
  static Glib::ustring i_gtk();
  static Glib::ustring i_boost();
  static Glib::ustring i_oniguruma();
  static Glib::ustring i_migemo();

public:
  EnvInfoDialog(Application &app, Gtk::Window &parent);
};

class AboutDialog : public Gtk::AboutDialog {
private:
  static Application *_app;

  static void install_url_hook(Application &app);
  static void url_hook(Gtk::AboutDialog    &dialog,
                       const Glib::ustring &uri);

private:
  Application &app_;

public:
  AboutDialog(Application &app, Gtk::Window &parent);
};

}/*gpyp*/

#endif/*DIALOG_H_*/
